package com.tuanzi.loan.workflow.service.impl;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.task.IdentityLink;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;
import com.tuanzi.loan.business.entity.system.SystemUser;
import com.tuanzi.loan.core.exception.SystemException;
import com.tuanzi.loan.core.vo.PageSearcher;
import com.tuanzi.loan.vo.request.system.ProcessDefinitionSearchRequest;
import com.tuanzi.loan.workflow.common.ActivityType;
import com.tuanzi.loan.workflow.entity.FormBinding;
import com.tuanzi.loan.workflow.entity.ScriptTask;
import com.tuanzi.loan.workflow.service.*;
import com.tuanzi.loan.workflow.vo.*;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

/**
 * @author Ray
 * @date 2018/01/16
 */
@Slf4j
@Service
@Transactional
public class WorkflowManagerServiceImpl extends WorkflowBaseService implements WorkflowManagerService {

	@Autowired
	private FormAttributeService formAttributeService;
	@Autowired
	private RejectConfigService rejectConfigService;
	@Autowired
	private FormRightService formRightService;
	@Autowired
	private FormBindingService formBindingService;
	@Autowired
	private ScriptTaskService scriptTaskService;
	@Autowired
	private StartPageService startPageService;
	// @Inject
	// private OpinionTagConfigService opinionTagConfigService;
	//
	// @Inject
	// private StrategyFlowService strategyFlowService;
	// @Resource
	// private FormBindingService formBindingService;
	// @Resource
	// private FormAttributeService formAttributeService;
	// @Resource
	// private FormRightService formRightService;
	// @Resource
	// private WorkflowScriptService workflowScriptService;
	// @Resource
	// private ProcInstMapper procInstMapper;
	// @Resource
	// private RejectConfigService rejectConfigService;

	@Override
	public String importProcessDefinition(String categoryId, InputStream workflowInputStream) {
		DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
		String resourceName = categoryId + ".bpmn";
		deploymentBuilder.addInputStream(resourceName, workflowInputStream);
		deploymentBuilder.category(categoryId);
		Deployment deployment = deploymentBuilder.deploy();

		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
		repositoryService.setProcessDefinitionCategory(processDefinition.getId(), categoryId);

		if (processDefinition.getVersion() > 1) {

			ProcessDefinition lastProcessDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processDefinition.getKey())
					.processDefinitionVersion(processDefinition.getVersion() - 1).singleResult();

			// 同步绑定表单
			formBindingService.synchronizeFormBinding(lastProcessDefinition.getId(), processDefinition.getId());

			// 同步表单权限
			formRightService.synchronizeFormRight(lastProcessDefinition.getId(), processDefinition.getId());

			// 同步绑定任务脚本
			scriptTaskService.synchronizeScriptTask(lastProcessDefinition.getId(), processDefinition.getId());

			// 同步回退节点配置
			rejectConfigService.synchronizeRejectConfig(lastProcessDefinition.getId(), processDefinition.getId());

			// 同步启动页面
			startPageService.synchronizeStartPage(lastProcessDefinition.getId(), processDefinition.getId());

			// 同步启动权限
			synchronizeStarter(lastProcessDefinition.getId(), processDefinition.getId());

		}

		return processDefinition.getId();
	}

	@Override
	public void exportProcessDefinition(List<String> procDefIds, OutputStream outputStream) {

		try (ZipOutputStream zos = new ZipOutputStream(outputStream)) {

			for (String procDefId : procDefIds) {
				ProcessDefinition procDef = repositoryService.getProcessDefinition(procDefId);
				List<String> resourceNames = repositoryService.getDeploymentResourceNames(procDef.getDeploymentId());
				for (Iterator<String> iterator = resourceNames.iterator(); iterator.hasNext();) {
					String resourceName = iterator.next();
					InputStream in = repositoryService.getResourceAsStream(procDef.getDeploymentId(), resourceName);
					writeFileToZip(resourceName, zos, in);
				}
			}

		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new SystemException("导出流程定义异常");
		}
	}

	@Override
	public List<ProcessDefinitionResponse> findAllVersionProcessDefinition(String procDefKey) {

		List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery().processDefinitionKey(procDefKey).orderByProcessDefinitionVersion().desc()
				.list();

		return structureProcessDefinitionResponseFrom(processDefinitions);
	}

	@Override
	public ProcessDefinitionResponse findLatestVersionProcessDefinitionByProcDefKey(String procDefKey) {
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().latestVersion().processDefinitionKey(procDefKey).singleResult();
		return structureProcessDefinitionResponseFrom(processDefinition);
	}

	// @Override
	// public ProcessDefinitionVO findProcessDefinitionByProcInstId(String
	// procInstId) {
	// String procDefId =
	// historyService.createHistoricProcessInstanceQuery().processInstanceId(procInstId).singleResult().getProcessDefinitionId();
	// ProcessDefinition procDef =
	// repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId).singleResult();
	// ProcessDefinitionVO procDefVO = mappingProcessDefinitionVO(procDef);
	// return procDefVO;
	// }
	//
	// @Override
	// public ProcessDefinitionVO findProcessDefinitionByProcDefId(String procDefId)
	// {
	// ProcessDefinition procDef =
	// repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId).singleResult();
	// ProcessDefinitionVO procDefVO = mappingProcessDefinitionVO(procDef);
	// return procDefVO;
	// }
	//
	// @Override
	// public ProcessDefinitionVO findProcessDefinitionByProcDefKey(String
	// procDefKey) {
	// ProcessDefinition procDef =
	// repositoryService.createProcessDefinitionQuery().processDefinitionKey(procDefKey).latestVersion().singleResult();
	// ProcessDefinitionVO procDefVO = mappingProcessDefinitionVO(procDef);
	// return procDefVO;
	// }
	//
	@Override
	public void deleteProcessDefinition(String procDefId) {
		ProcessDefinition procDef = repositoryService.getProcessDefinition(procDefId);

		if (procDef == null) {
			log.error("流程定义不存在 procDefId : {} ", procDefId);
			throw new SystemException("流程定义不存在 procDefId : " + procDefId);
		}

		if (countProcInstByProcDefId(procDef.getId()) > 0) {
			log.warn("流程【{}】定义下含有流程实例，不能删除！ procDefId : {}", procDef.getName(), procDefId);
			throw new SystemException("流程【" + procDef.getName() + "】定义下含有流程实例，不能删除！");
		}

		formBindingService.deleteByProcDefId(procDefId);
		formAttributeService.deleteByProcDefId(procDefId);
		formRightService.deleteByProcDefId(procDefId);
		scriptTaskService.deleteByProcDefId(procDefId);
		rejectConfigService.deleteByProcDefId(procDefId);
		repositoryService.deleteDeployment(procDef.getDeploymentId());
	}

	@Override
	public void deleteProcessDefinition(List<String> procDefIds) {
		procDefIds.stream().forEach(this::deleteProcessDefinition);
	}

	public void suspendProcessDefinition(String procDefId) {
		ProcessDefinition processDefinition = repositoryService.getProcessDefinition(procDefId);

		if (processDefinition == null) {
			log.error("流程定义不存在 procDefId : {} ", procDefId);
			throw new SystemException("流程定义不存在 procDefId : " + procDefId);
		}

		if (!processDefinition.isSuspended()) {
			repositoryService.suspendProcessDefinitionById(procDefId, false, null);
		}
	}

	public void suspendProcessDefinition(List<String> procDefIds) {
		procDefIds.stream().forEach(this::suspendProcessDefinition);
	}

	/**
	 * 职责：根据流程定义ID启用流程
	 *
	 * @param procDefId
	 */
	public void activeProcessDefinition(String procDefId) {
		ProcessDefinition processDefinition = repositoryService.getProcessDefinition(procDefId);

		if (processDefinition == null) {
			log.error("流程定义不存在 procDefId : {} ", procDefId);
			throw new SystemException("流程定义不存在 procDefId : " + procDefId);
		}

		if (processDefinition.isSuspended()) {
			repositoryService.activateProcessDefinitionById(procDefId, true, null);
		}
	}

	/**
	 * 职责：根据流程定义ID启用流程
	 *
	 * @param procDefIds
	 */
	public void activeProcessDefinition(List<String> procDefIds) {
		procDefIds.stream().forEach(this::activeProcessDefinition);
	}

	//
	// @Override
	// public List<ProcessInstanceVO> findAllProcessInstance() {
	// List<ProcessInstanceVO> piVOList = new ArrayList<ProcessInstanceVO>();
	// List<HistoricProcessInstance> piList =
	// historyService.createHistoricProcessInstanceQuery().orderByProcessInstanceStartTime().desc().list();
	//
	// for (Iterator<HistoricProcessInstance> iterator = piList.iterator();
	// iterator.hasNext();) {
	// HistoricProcessInstance hisProcInst = iterator.next();
	// ProcessDefinition procDef =
	// repositoryService.createProcessDefinitionQuery().processDefinitionId(hisProcInst.getProcessDefinitionId()).singleResult();
	//
	// ProcessInstanceVO piVO = new ProcessInstanceVO();
	// BeanUtils.copyProperties(hisProcInst, piVO);
	//
	// piVO.setCategory(procDef.getCategory());
	// if (StringUtils.isNotBlank(procDef.getCategory())) {
	// Dic dic = this.getCategoryDic(procDef.getCategory());
	// if (dic != null) {
	// piVO.setCategoryName(dic.getDicDataName());
	// }
	// }
	//
	// piVOList.add(piVO);
	// }
	//
	// return piVOList;
	// }
	//
	// @Override
	// public List<ProcessInstanceVO> findAllProcessInstanceByProcDefKey(String
	// procDefKey) {
	// List<ProcessInstanceVO> piVOList = new ArrayList<ProcessInstanceVO>();
	// // 查找 procDefKey 下的所有processDefinition
	// ProcessDefinitionQuery procDefQuery =
	// repositoryService.createProcessDefinitionQuery();
	// procDefQuery.processDefinitionKey(procDefKey);
	// List<ProcessDefinition> processDefinitionList = procDefQuery.list();
	//
	// for (ProcessDefinition procDef : processDefinitionList) {
	// List<HistoricProcessInstance> piList =
	// historyService.createHistoricProcessInstanceQuery().processDefinitionId(procDef.getId()).list();
	//
	// for (HistoricProcessInstance hiProcInst : piList) {
	// ProcessInstanceVO piVO = new ProcessInstanceVO();
	// BeanUtils.copyProperties(hiProcInst, piVO);
	// piVO.setCategory(procDef.getCategory());
	// if (StringUtils.isNotBlank(procDef.getCategory())) {
	// Dic dic = this.getCategoryDic(procDef.getCategory());
	// if (dic != null) {
	// piVO.setCategoryName(dic.getDicDataName());
	// }
	// }
	//
	// piVOList.add(piVO);
	// }
	//
	// }
	//
	// return piVOList;
	// }
	//
	// private void loadCategoryName(List<ProcessInstanceVO> procInstVOResponseList)
	// {
	// String categoryName = null;
	// for (ProcessInstanceVO processInstanceVO : procInstVOResponseList) {
	// Dic dic = this.getCategoryDic(processInstanceVO.getCategory());
	// if (dic != null) {
	// categoryName = dic.getDicDataName();
	// }
	// processInstanceVO.setCategoryName(categoryName);
	// }
	//
	// }
	//
	// private void loadStartUserName(List<ProcessInstanceVO>
	// procInstVOResponseList) {
	// Set<String> userIds = new HashSet<String>();
	// for (ProcessInstanceVO piVO : procInstVOResponseList) {
	// userIds.add(piVO.getStartUserId());
	// }
	// List<String> users = Lists.newArrayList();
	// users.addAll(userIds);
	// List<User> userList = userService.getUsersByAccounts(users);
	//
	// Map<String, String> userMap = new HashMap<String, String>();
	// for (User user : userList) {
	// userMap.put(user.getUserAccount(), user.getUserName());
	// }
	//
	// for (ProcessInstanceVO procInstVO : procInstVOResponseList) {
	// procInstVO.setStartUserName(userMap.get(procInstVO.getStartUserId()));
	// }
	// }
	//
	// @Override
	// public DatatablesPageResponse<ProcessInstanceVO>
	// findEndedProcessInstance(ProcInstQueryRequest request) {
	// PageHelper.startPage(Integer.parseInt(request.getStart()),
	// Integer.parseInt(request.getLength()));
	// List<ProcessInstance> procInstResponseList =
	// procInstMapper.listEndedProcInst(ObjUtil.objectToMap(request));
	// List<ProcessInstanceVO> procInstVOResponseList = new
	// ArrayList<>(procInstResponseList.size());
	// ObjUtil.listObjectToListObject(procInstResponseList, procInstVOResponseList,
	// ProcessInstanceVO.class);
	// PageInfo<ProcessInstanceVO> pageInfo = new
	// PageInfo<>(procInstVOResponseList);
	// return new DatatablesPageResponse<>(request.getDraw(),
	// Long.toString(pageInfo.getTotal()), pageInfo.getList());
	// }
	//
	// @Override
	// public ProcessInstanceVO findProcessInstance(String procInstId) {
	// HistoricProcessInstance instance =
	// historyService.createHistoricProcessInstanceQuery().processInstanceId(procInstId).singleResult();
	// ProcessInstanceVO processInstanceVO = new ProcessInstanceVO();
	// BeanUtils.copyProperties(instance, processInstanceVO);
	// return processInstanceVO;
	// }
	//
	@Override
	public InputStream getDeploymentBpmn(String deployId) {
		return this.getDeploymentResource(deployId, ActivitiResourceType.BPM);
	}

	@Override
	public InputStream getDeploymentImage(String deploymentId) {
		return this.getDeploymentResource(deploymentId, ActivitiResourceType.IMAGE);
	}

	@Override
	public List<ActivityResponse> findAllUserTaskActivity(String procDefId) {
		List<ActivityResponse> activityResponses = Lists.newArrayList();

		ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(procDefId);
		List<ActivityImpl> activityImpls = processDefinitionEntity.getActivities();
		for (ActivityImpl activityImpl : activityImpls) {
			ActivityResponse activityResponse = this.mappingUserTaskActivityImpl2ActivityResponse(activityImpl, null);
			if (activityResponse != null) {
				activityResponses.add(activityResponse);
			}
		}
		return activityResponses;
	}

	@Override
	public ActivityResponse findFirstUserTaskActivity(String procDefId) {
		ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(procDefId);
		List<ActivityImpl> activityImpls = processDefinitionEntity.getActivities();

		if (CollectionUtils.isNotEmpty(activityImpls)) {
			return this.mappingUserTaskActivityImpl2ActivityResponse(activityImpls.get(0), null);
		}
		return null;
	}

	@Override
	public List<ActivityResponse> findAllActivity(String procDefId) {
		ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(procDefId);

		List<ActivityResponse> activityResponses = Lists.newArrayList();
		// 根据流程定义获得所有的节点：
		List<ActivityImpl> activities = processDefinitionEntity.getActivities();
		for (ActivityImpl activityImpl : activities) {

			ActivityResponse activityResponse = null;

			if (isUserTask(activityImpl)) {
				activityResponse = this.mappingUserTaskActivityImpl2ActivityResponse(activityImpl, null);
			} else {
				activityResponse = this.mappingServiceTaskActivityImpl2ActivityResponse(activityImpl, null);
			}

			if (activityResponse == null) {
				continue;
			}

			FormBinding formBinding = formBindingService.findByProcDefIdAndActId(procDefId, activityImpl.getId());
			if (formBinding != null) {
				activityResponse.setFormUrl(formBinding.getFormUrl());
			}
			activityResponse.setScriptTasks(scriptTaskService.findAllByProcDefIdAndActivityId(procDefId, activityResponse.getId()));

			activityResponses.add(activityResponse);
		}

		return activityResponses;
	}

	@Override
	public void saveActivity(String procDefId, List<ActivityResponse> activityResponses) {
		try {
			// 获取流程定义bpmn文件
			ProcessDefinitionQuery procDefQuery = repositoryService.createProcessDefinitionQuery();
			ProcessDefinition procDef = procDefQuery.processDefinitionId(procDefId).singleResult();
			String categoryId = procDef.getCategory();

			InputStream in = repositoryService.getProcessModel(procDefId);
			SAXReader reader = new SAXReader();
			Document xmlDoc = reader.read(in);

			Element e = xmlDoc.getRootElement();
			List tmp = e.elements("process");
			Element processNode = (Element) tmp.get(0);
			List node = processNode.elements();

			for (Iterator iterator = node.iterator(); iterator.hasNext();) {
				Element el = (Element) iterator.next();
				log.info(el.asXML());
				if (StringUtils.equals(ActivityType.USER_EVENT.getValue(), el.getName())) {
					String id = el.attributeValue("id");
					for (ActivityResponse activityResponse : activityResponses) {

						if (!activityResponse.getActivityId().equals(id)) {
							continue;
						}

						// 清理旧数据
						Attribute assignee = el.attribute("assignee");
						if (assignee != null) {
							el.remove(assignee);
						}
						Attribute candidateUsers = el.attribute("candidateUsers");
						if (candidateUsers != null) {
							el.remove(candidateUsers);
						}
						Attribute candidateGroups = el.attribute("candidateGroups");
						if (candidateGroups != null) {
							el.remove(candidateGroups);
						}

						if (CollectionUtils.isEmpty(activityResponse.getAssignees())) {
							// 设置执行者变量
							if (StringUtils.isNotBlank(activityResponse.getAssigneeVariable())) {
								log.info("设置执行者变量：" + activityResponse.getAssigneeVariable());
								el.addAttribute("activiti:assignee", activityResponse.getAssigneeVariable());
							}
						} else {
							// 设置候选人
							StringBuilder assigneeStr = new StringBuilder();
							StringBuilder assigneeGroupStr = new StringBuilder();
							for (AssigneeResponse assigneeResponse : activityResponse.getAssignees()) {
								if (assigneeResponse.getAssigneeType() == AssigneeType.USER) {
									// 用逗号分割每个执行者，例如:1,2,3
									assigneeStr.append(assigneeResponse.getAssignee()).append(",");
								} else if (assigneeResponse.getAssigneeType() == AssigneeType.ROLE || assigneeResponse.getAssigneeType() == AssigneeType.DEPT) {
									// 用逗号分割每个执行者，例如:role_1,dept_1,user_1
									assigneeGroupStr.append(assigneeResponse.getAssigneeType()).append("_").append(assigneeResponse.getAssignee()).append(",");
								} else {
									throw new RuntimeException("不支持的执行者类型：AssigneeType=" + assigneeResponse.getAssigneeType());
								}
							}

							String allAssigneeStr = assigneeStr.toString();
							if (StringUtils.isNotBlank(allAssigneeStr)) {
								allAssigneeStr = allAssigneeStr.substring(0, allAssigneeStr.lastIndexOf(","));
								el.addAttribute("activiti:candidateUsers", allAssigneeStr);
							}

							String allAssigneeGroupStr = assigneeGroupStr.toString();
							if (StringUtils.isNotBlank(allAssigneeGroupStr)) {
								allAssigneeGroupStr = allAssigneeGroupStr.substring(0, allAssigneeGroupStr.lastIndexOf(","));
								el.addAttribute("activiti:candidateGroups", allAssigneeGroupStr);
							}
						}
					}
				}
			}

			// 部署bpmn文件，流程版本+1
			InputStream inBpmn = new ByteArrayInputStream(xmlDoc.asXML().getBytes(StandardCharsets.UTF_8));
			String newProcDefId = this.importProcessDefinition(categoryId, inBpmn);

			for (ActivityResponse activityResponse : activityResponses) {

				if (StringUtils.isNotBlank(activityResponse.getFormUrl())) {
					FormBinding formBinding = formBindingService.findByProcDefIdAndActId(newProcDefId, activityResponse.getId());
					if (formBinding == null) {
						formBinding = new FormBinding();
						formBinding.setActId(activityResponse.getId());
						formBinding.setProcDefId(newProcDefId);
					}
					formBinding.setFormUrl(activityResponse.getFormUrl());
					formBindingService.saveOrUpdate(formBinding);
				}

				for (ScriptTask scriptTask : activityResponse.getScriptTasks()) {
					ScriptTask dbScriptTask = scriptTaskService.findByProcDefIdAndActivityIdAndTaskType(newProcDefId, activityResponse.getActivityId(), scriptTask.getTaskType());

					if (StringUtils.isBlank(scriptTask.getContent()) && dbScriptTask != null) {
						scriptTaskService.delete(dbScriptTask);
						continue;
					}

					if (StringUtils.isBlank(scriptTask.getContent())) {
						continue;
					}

					if (dbScriptTask == null) {
						dbScriptTask = new ScriptTask();
						dbScriptTask.setProcDefId(newProcDefId);
						dbScriptTask.setActivityId(activityResponse.getId());
						dbScriptTask.setTaskType(scriptTask.getTaskType());
					}
					dbScriptTask.setContent(scriptTask.getContent());
					scriptTaskService.saveOrUpdate(dbScriptTask);
				}

			}

		} catch (DocumentException e) {
			throw new SystemException("保存流程节点异常");
		}
	}

	@Override
	public ActivityResponse findActivity(String procDefId, String activityId) {
		return findAllActivity(procDefId).parallelStream().filter(x -> activityId.equals(x.getActivityId())).findFirst().orElse(null);
	}

	@Override
	public boolean isExitsProcessDefinitionByProcDefKey(String procDefKey) {
		return repositoryService.createProcessDefinitionQuery().processDefinitionKey(procDefKey).count() > 0;
	}

	@Override
	public boolean isExitsProcessDefinitionByProcDefId(String procDefId) {
		return repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId).count() > 0;
	}

	public Long countProcInstByProcDefId(String procDefId) {
		return historyService.createHistoricProcessInstanceQuery().processDefinitionId(procDefId).count();
	}

	@Override
	public List<SystemUser> findFirstActivitySystemUserProcDefKey(String procDefKey) {
		ProcessDefinitionResponse processDefinitionResponse = findLatestVersionProcessDefinitionByProcDefKey(procDefKey);
		ActivityResponse activityResponse = findFirstUserTaskActivity(processDefinitionResponse.getId());
		if (activityResponse == null) {
			return Lists.newArrayList();
		}
		return findSystemUserByAssignees(activityResponse.getAssignees());
	}

	@Override
	public List<SystemUser> findSystemUserByAssignees(List<AssigneeResponse> assigneeResponses) {
		List<SystemUser> systemUsers = Lists.newArrayList();

		for (AssigneeResponse assigneeResponse : assigneeResponses) {
			switch (assigneeResponse.getAssigneeType()) {
			case ROLE:
				systemUsers.addAll(systemUserService.findAllByRoleCode(assigneeResponse.getAssignee()));
				break;
			case USER:
				systemUsers.add(systemUserService.findOneByAccount(assigneeResponse.getAssignee()));
				break;
			case DEPT:
				break;
			default:
				throw new SystemException("不支持执行者类型：AssigneeType=" + assigneeResponse.getAssigneeType());
			}
		}

		return systemUsers.stream().distinct().sorted(Comparator.comparing(SystemUser::getAccount)).collect(Collectors.toList());
	}

	//
	// @Transactional
	// @Override
	// public ProcessDefinitionVO updateProcessDefinitionVersion(String procDefId) {
	// try {
	// return doUpdateProcessDefinitionVersion(procDefId);
	// } catch (IOException e) {
	// String msg = "更新流程定义版本异常";
	// throw new ServiceException(ErrorResponseEnum.SYSTEM_ERROR.getCode(), msg);
	// }
	// }
	//
	// @Override
	// public void updateDeployment(String procDefId, byte[] bpmn) {
	// // ProcessDefinition procDef =
	// repositoryService.createProcessDefinitionQuery(
	// // ).processDefinitionId( procDefId ).singleResult( );
	// // Cnd cnd = Cnd.where( "NAME_" , "like" , "%.bpmn" ).and( "DEPLOYMENT_ID_" ,
	// // "=" , procDef.getDeploymentId( ) );
	// // List < Record > records = this.dao.query( "ACT_GE_BYTEARRAY" , cnd );
	// // if ( CollectionUtils.isEmpty( records ) ) {
	// // logger.error( "更新部署模型失败！" );
	// // return;
	// // }
	// //
	// // String byteId = records.get( 0 ).getString( "ID_" );
	// // DeploymentByteVO vo = new DeploymentByteVO( );
	// // vo.setId( byteId );
	// // vo.setBytes( bpmn );
	// // this.dao.updateIgnoreNull( vo );
	// }
	//
	// @Override
	// public void updateOpinionListDef(String procDefKey) {
	//
	// }
	//
	// @Override
	// public BaseResponse<List<ActivityVO>>
	// getAllActListByProcDefKey(AllActivityGetRequest request) {
	//
	// ProcessDefinitionVO proDef =
	// findProcessDefinitionByProcDefKey(request.getProcDefKey());
	// if (null != proDef) {
	// request.setProcDefId(proDef.getId());
	// return getAllActivity(request);
	// }
	// return new BaseResponse<>(new BaseResult<>(false, "不存在的流程定义key: " +
	// request.getProcDefKey()));
	// }
	//
	// @Override
	// public List<String> findProcessInstanceIdByProcDefKeyActivityId(String
	// procDefKey, String activityId) {
	// List<String> processInstanceIdList = new ArrayList<>();
	// // 根据流程编号，获取所有流程定义
	// List<ProcessDefinition> procDefList =
	// this.repositoryService.createProcessDefinitionQuery().processDefinitionKey(procDefKey).list();
	//
	// // 遍历每个流程定义
	// for (ProcessDefinition procDef : procDefList) {
	// // 根据流程定义key和当前环节id获取实例ID
	// List<Task> list =
	// this.taskService.createTaskQuery().processDefinitionId(procDef.getId()).taskDefinitionKey(activityId).list();
	//
	// for (Task task : list) {
	// processInstanceIdList.add(task.getProcessInstanceId());
	// }
	// }
	// return processInstanceIdList;
	// }

	@Override
	public Page<ProcessDefinitionResponse> listLastVersionProcessDefinition(PageSearcher<ProcessDefinitionSearchRequest> request) {

		ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();

		ProcessDefinitionSearchRequest searchCondition = request.getSearchCondition();
		Pageable pageable = request.getPageable();

		if (StringUtils.isNotBlank(searchCondition.getCategory()))
			query.processDefinitionCategory(searchCondition.getCategory());

		if (StringUtils.isNotBlank(searchCondition.getName()))
			query.processDefinitionNameLike("%" + searchCondition.getName() + "%");

		if (StringUtils.isNotBlank(searchCondition.getCode()))
			query.processDefinitionKeyLike("%" + searchCondition.getCode() + "%");

		if (searchCondition.getCurrentVersion() != null)
			query.processDefinitionVersion(searchCondition.getCurrentVersion());

		long total = query.latestVersion().count();

		List<ProcessDefinition> processDefinitions = query.latestVersion().orderByProcessDefinitionKey().asc().listPage((pageable.getOffset()), pageable.getPageSize());
		List<ProcessDefinitionResponse> processDefinitionResponses = structureProcessDefinitionResponseFrom(processDefinitions);

		return new PageImpl<ProcessDefinitionResponse>(processDefinitionResponses, request.getPageable(), total);
	}

	private static void writeFileToZip(String resourceName, ZipOutputStream zos, InputStream in) throws IOException {
		ZipEntry ze = new ZipEntry(resourceName);
		zos.putNextEntry(ze);
		BufferedInputStream bis = new BufferedInputStream(in);
		byte[] buf = new byte[1024];
		int len;
		try {
			while ((len = bis.read(buf)) > 0) {
				zos.write(buf, 0, len);
			}
		} finally {
			bis.close();
			in.close();
			zos.closeEntry();
		}
	}

	//
	// /**
	// * 获取流程定义部署资源
	// *
	// * @param deployId
	// * 部署id
	// * @param resourceType
	// * 资源类型：1-bpmn定义文件，2-流程图片
	// * @return
	// */
	private InputStream getDeploymentResource(String deployId, ActivitiResourceType activitiResourceType) {

		if (activitiResourceType == null) {
			log.warn("不支持的资源类型");
		}

		// 获取图片资源名称
		List<String> resourceNames = repositoryService.getDeploymentResourceNames(deployId);
		if (CollectionUtils.isEmpty(resourceNames)) {
			return null;
		}

		// 定义图片资源的名称
		String resourceName = null;
		for (String name : resourceNames) {
			if (name.indexOf(activitiResourceType.getSuffix()) >= 0) {
				resourceName = name;
			}
		}

		return repositoryService.getResourceAsStream(deployId, resourceName);
	}

	// private ProcessDefinitionVO doParseBpmnFile(InputStream in) throws
	// DocumentException {
	// SAXReader reader = new SAXReader();
	// Document xmlDoc = reader.read(in);
	// // logger.error(xmlDoc.asXML());
	//
	// // 获取processDefinationKey
	// Element e = xmlDoc.getRootElement();
	// List tmp = e.elements("process");
	// Element processNode = (Element) tmp.get(0);
	// String procDefKey = processNode.attributeValue("id");
	// String procDefName = processNode.attributeValue("name");
	//
	// ProcessDefinitionVO procDefVO = new ProcessDefinitionVO();
	// procDefVO.setKey(procDefKey);
	// procDefVO.setName(procDefName);
	//
	// return procDefVO;
	// }
	//
	// private ProcessDefinitionVO doUpdateProcessDefinitionVersion(String
	// procDefId) throws IOException {
	// ProcessDefinitionQuery procDefQuery =
	// repositoryService.createProcessDefinitionQuery();
	// ProcessDefinition procDef =
	// procDefQuery.processDefinitionId(procDefId).singleResult();
	// if (procDef == null) {
	// return null;
	// }
	//
	// InputStream inBpmn = null;
	// InputStream inImage = null;
	// ProcessDefinitionVO procDefVO = null;
	//
	// try {
	// inBpmn = this.getDeploymentBpmn(procDef.getDeploymentId());
	// inImage = this.getDeploymentImage(procDef.getDeploymentId());
	// procDefVO = this.importProcessDefinition(inBpmn, inImage,
	// procDef.getCategory());
	// } finally {
	// if (inBpmn != null) {
	// inBpmn.close();
	// }
	// if (null != inImage) {
	// inImage.close();
	// }
	// }
	//
	// return procDefVO;
	// }
	//

	@Override
	public void addStarter(List<StarterResponse> starters) {
		for (StarterResponse starterResponse : starters) {

			ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(starterResponse.getProcDefId()).singleResult();

			if (processDefinition == null) {
				log.error("不存在流程定义 : {}", starterResponse.getProcDefId());
				continue;
			}

			switch (starterResponse.getStarterType()) {

			case USER:
				repositoryService.addCandidateStarterUser(processDefinition.getId(), starterResponse.getStarter());
				break;
			case ROLE:
				repositoryService.addCandidateStarterGroup(processDefinition.getId(), StarterType.ROLE.name() + "_" + starterResponse.getStarter());
				break;
			default:
				log.error("不存在对应starterType : {}", starterResponse.getStarterType());
				break;
			}
		}
	}

	@Override
	public void removeStarter(List<StarterResponse> starters) {
		for (StarterResponse starterResponse : starters) {

			ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(starterResponse.getProcDefId()).singleResult();

			if (processDefinition == null) {
				log.error("不存在流程定义 : {}", starterResponse.getProcDefId());
				continue;
			}

			switch (starterResponse.getStarterType()) {

			case USER:
				repositoryService.deleteCandidateStarterUser(processDefinition.getId(), starterResponse.getStarter());
				break;
			case ROLE:
				repositoryService.deleteCandidateStarterGroup(processDefinition.getId(), StarterType.ROLE.name() + "_" + starterResponse.getStarter());
				break;
			default:
				log.error("不存在对应starterType : {}", starterResponse.getStarterType());
				break;
			}
		}
	}

	@Override
	public ProcessDefinitionResponse findOneByProcDefId(String procDefId) {
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId).singleResult();
		if (processDefinition == null) {
			log.error("不存在流程定义 : {}", procDefId);
			return null;
		}
		return structureProcessDefinitionResponseFrom(processDefinition);
	}

	@Override
	public List<StarterResponse> findStarterBy(String procDefId) {
		List<IdentityLink> identityLinks = repositoryService.getIdentityLinksForProcessDefinition(procDefId);

		List<String> distinctUser = identityLinks.stream().filter(x -> StringUtils.isNotBlank(x.getUserId())).map(IdentityLink::getUserId).distinct().collect(Collectors.toList());

		List<String> distinctRole = identityLinks.stream().filter(x -> StringUtils.isNotBlank(x.getGroupId()) && StringUtils.startsWith(x.getGroupId(), StarterType.ROLE.name()))
				.map(IdentityLink::getGroupId).map(x -> StringUtils.replace(x, StarterType.ROLE.name() + "_", "")).distinct().collect(Collectors.toList());

		List<StarterResponse> userStarter = systemUserService.findAllByAccounts(distinctUser).stream().map(x -> {
			StarterResponse response = new StarterResponse();
			response.setStarter(x.getAccount());
			response.setProcDefId(procDefId);
			response.setStarterType(StarterType.USER);
			response.setStarterName(x.getName());
			return response;
		}).collect(Collectors.toList());

		List<StarterResponse> roleStarter = roleService.findAllByCodes(distinctRole).stream().map(x -> {
			StarterResponse response = new StarterResponse();
			response.setStarter(x.getCode());
			response.setProcDefId(procDefId);
			response.setStarterType(StarterType.ROLE);
			response.setStarterName(x.getName());
			return response;
		}).collect(Collectors.toList());

		List<StarterResponse> starterResponses = Lists.newArrayList();
		starterResponses.addAll(userStarter);
		starterResponses.addAll(roleStarter);

		return starterResponses;
	}

	private void synchronizeStarter(String oldProcDefId, String newProcDefId) {
		List<IdentityLink> identityLinks = repositoryService.getIdentityLinksForProcessDefinition(oldProcDefId);
		for (IdentityLink identityLink : identityLinks) {

			if (StringUtils.isNotBlank(identityLink.getUserId())) {
				repositoryService.addCandidateStarterUser(newProcDefId, identityLink.getUserId());
				continue;
			}

			if (StringUtils.isNotBlank(identityLink.getGroupId())) {
				repositoryService.addCandidateStarterGroup(newProcDefId, identityLink.getGroupId());
			}

		}
	}

	enum ActivitiResourceType {
		IMAGE(".png"), BPM(".bpmn");

		@Getter
		private String suffix;

		ActivitiResourceType(String suffix) {
			this.suffix = suffix;
		}
	}

}
